package com.jzo2o.foundations.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
import com.jzo2o.common.enums.EnableStatusEnum;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.*;
import com.jzo2o.foundations.model.domain.*;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.jzo2o.foundations.constants.RedisConstants.CacheManager.*;
import static com.jzo2o.foundations.constants.RedisConstants.CacheName.*;

@Service
@Slf4j
public class IServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {
    @Resource
    private ServeItemMapper itemMapper;
    @Resource
    private RegionMapper regionMapper;
    @Resource
    private IServeItemService serveItemService;


    /**
     * 查询区域设置的服务
     * @param dto 数据
     * @return PageResult
     */
    @Override
    public PageResult<ServeResDTO> pageServe(ServePageQueryReqDTO dto) {
        return PageHelperUtils.selectPage(dto,
                () -> baseMapper.selectregionSetServe(dto.getRegionId()));
    }

    /**
     * 添加/批量添加区域服务
     * @param serveDTO 数据
     */
    @Override
    public void batch(List<ServeUpsertReqDTO> serveDTO) {
        // 数据健壮性判断
        for (ServeUpsertReqDTO serve : serveDTO) {
            ServeItem serveItem = itemMapper.selectById(serve.getServeItemId());
            // 判断添加的服务项是否存在or服务项是否启用
            if(!(ObjectUtils.isEmpty(serveItem) ||
                    serveItem.getActiveStatus() != EnableStatusEnum.ENABLE.getStatus())) {
                throw new ForbiddenOperationException("添加的服务项不存在或服务项未启用");
            }

            // 判断区域服务是否重复添加
            Integer count = lambdaQuery()
                    .eq(Serve::getRegionId, serve.getRegionId())
                    .eq(Serve::getServeItemId, serve.getServeItemId())
                    .count();
            if(count >= 1) {
                throw new ForbiddenOperationException("重复添加区域服务");
            }

            // 数据封装
            Serve copyServe = BeanUtils.copyBean(serve, Serve.class);
            Region region = regionMapper.selectById(serve.getRegionId());
            String cityCode = region.getCityCode();
            copyServe.setCityCode(cityCode);

            baseMapper.insert(copyServe);

            // 数据同步
            dataSync(copyServe.getId());
        }
    }

    /**
     * 修改区域服务价格
     * @param id 区域服务id
     * @param price 修改后的价格
     */
    @Override
    public void updatePrice(Long id, BigDecimal price) {
        Serve serve = baseMapper.selectById(id);
        if(serve.getSaleStatus() == 2) {
            throw new ForbiddenOperationException("区域服务上架状态不允许修改价格");
        }

        // 数据同步
        ServeSync serveSync = new ServeSync();
        serveSync.setPrice(price);
        serveSync.setId(id);
        serveSyncMapper.updateById(serveSync);

        // 更新
        lambdaUpdate()
                .set(Serve::getPrice, price)
                .eq(Serve::getId, id)
                .update();
    }

    /**
     * 区域服务上架
     * @param id 区域服务id
     */
    @Override
    public void onSala(Long id) {
        // 判断区域服务是否满足条件
        Serve serve = baseMapper.selectById(id);
        // 区域服务只有在草稿和下架状态才可以上架
        Integer saleStatus = serve.getSaleStatus();
        if(!(saleStatus == FoundationStatusEnum.DISABLE.getStatus()
                || saleStatus == FoundationStatusEnum.INIT.getStatus())) {
            throw new ForbiddenOperationException("区域服务只有在草稿和下架状态才可以上架");
        }

        // 判断服务项是否是启用状态
        ServeItem serveItem = itemMapper.selectById(serve.getServeItemId());
        if(!(serveItem.getActiveStatus() == FoundationStatusEnum.ENABLE.getStatus())) {
            throw new ForbiddenOperationException("服务项为启用");
        }

        // 数据同步
        dataSync(serve.getId());

        // 更新
        lambdaUpdate()
                .set(Serve::getSaleStatus, FoundationStatusEnum.ENABLE.getStatus())
                .eq(Serve::getId, id)
                .update();
    }

    /**
     * 删除区域服务
     * @param id 区域服务id
     */
    @Override
    public void delete(Long id) {
        // 删除的前提是区域服务是在草稿和下架状态
        Serve serve = baseMapper.selectById(id);
        Integer saleStatus = serve.getSaleStatus();
        if(!(saleStatus == FoundationStatusEnum.INIT.getStatus()
                || saleStatus == FoundationStatusEnum.DISABLE.getStatus())) {
            throw new ForbiddenOperationException("区域服务已上架不可删除");
        }

        int i = baseMapper.deleteById(id);
        if(i == 0) {
            throw new CommonException("删除的区域服务不存在");
        }
    }

    /**
     * 区域服务下架
     * @param id 区域服务id
     */
    @Override
    public void offSale(Long id) {
        // 区域服务只有在上架状态时才可以下架
        Serve serve = baseMapper.selectById(id);
        Integer saleStatus = serve.getSaleStatus();
        if(!(saleStatus == FoundationStatusEnum.ENABLE.getStatus())) {
            throw new ForbiddenOperationException("区域服务只有在上架状态时才可以下架");
        }

        // 同步数据
        serveSyncMapper.deleteById(id);

        lambdaUpdate()
                .set(Serve::getSaleStatus, FoundationStatusEnum.DISABLE.getStatus())
                .eq(Serve::getId, id)
                .update();
    }

    /**
     * 区域服务设置为热门
     * @param id 区域服务
     */
    @Override
    public void onHot(Long id) {
        // 上架的服务才可以设置热门
        Serve serve = baseMapper.selectById(id);
        if(ObjectUtils.isNull(serve)) {
            throw new ForbiddenOperationException("您所设置的服务不存在");
        }

        serve.setIsHot(1);
        serve.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(serve);
    }

    /**
     * 区域服务取消热门
     * @param id 区域服务id
     */
    @Override
    public void offHot(Long id) {
        Serve serve = baseMapper.selectById(id);
        if(ObjectUtils.isNull(serve)) {
            throw new ForbiddenOperationException("您所设置的服务不存在");
        }

        lambdaUpdate()
                .set(Serve::getIsHot, 0)
                .eq(Serve::getId, id)
                .update();
    }

    /**
     * 查询首页服务类型列表
     * @param id 区域id
     * @return List
     */
    @Caching(
      cacheable = {
        @Cacheable(value = SERVE_ICON, key = "#id", unless = "#result.size() != 0", cacheManager = THIRTY_MINUTES),
        @Cacheable(value = SERVE_ICON, key = "#id", unless = "#result.size() == 0", cacheManager = FOREVER)
      }
    )
    @Override
    public List<ServeCategoryResDTO> firstPageServeList(Long id) {
        // 参数校验
        if(ObjectUtils.isNull(id)) {
            return Collections.emptyList();
        }

        // 查询首页服务服务类型，以及对应类型的服务项,并校验
        List<ServeCategoryResDTO> scr
                = baseMapper.selectServeTypeList(id);
        if(ObjectUtils.isEmpty(scr)) {
            return Collections.emptyList();
        }

        // 参数处理
        // 服务类型最大显示数量为2，对应的服务项最大显示4个
        int index = Math.min(scr.size(), 2);
        // 服务类型数量处理
        List<ServeCategoryResDTO> handlerList = new ArrayList<>(scr.subList(0, index));
        handlerList.forEach(item -> {
            // 服务项数量处理
            List<ServeSimpleResDTO> ssrd = item.getServeResDTOList();
            int index1 = Math.min(ssrd.size(), 2);
            item.setServeResDTOList(new ArrayList<>(ssrd.subList(0, index1)));
        });

        return handlerList;
    }

    /**
     * 查询服务类型列表
     *
     * @param id 区域id
     * @return
     */
    @Caching(
      cacheable = {
        @Cacheable(value = SERVE_TYPE, key = "#id", unless = "#result.size() != 0", cacheManager = THIRTY_MINUTES),
        @Cacheable(value = SERVE_TYPE, key = "#id", unless = "#result.size() == 0", cacheManager = FOREVER)
      }
    )
    @Override
    public List<ServeType> selectServeTypeList(Long id) {
        // 参数校验
        if(ObjectUtils.isNull(id)) {
            return Collections.emptyList();
        }
        List<ServeType> serveType = baseMapper.getServeType(id);
        if(ObjectUtils.isEmpty(serveType)) {
            return Collections.emptyList();
        }
        return serveType;
    }

    /**
     * 查询首页热门服务数据
     * @param id 区域id
     * @return List
     */
    @Caching(
     cacheable = {
       @Cacheable(value = HOT_SERVE, key = "#id", unless = "#result.size() != 0", cacheManager = THIRTY_MINUTES),
       @Cacheable(value = HOT_SERVE, key = "#id", unless = "#result.size() == 0", cacheManager = FOREVER)
     }
    )
    @Override
    public List<ServeAggregationSimpleResDTO> hotServeList(Long id) {
        if(ObjectUtils.isNull(id)) {
            return Collections.emptyList();
        }

        List<ServeAggregationSimpleResDTO> hotServeList = baseMapper.getHotServe(id);
        if(ObjectUtils.isEmpty(hotServeList)) {
            return Collections.emptyList();
        }
        return hotServeList;
    }

    /**
     * 根据id查询服务信息
     *
     * @param id 服务id
     * @return ServeResDTO
     */
    @Caching(
      cacheable = {
        @Cacheable(value = JZ_CACHE + ":SERVE", key = "#id", unless = "#result != null", cacheManager = ONE_DAY),
        @Cacheable(value = JZ_CACHE + ":SERVE", key = "#id", unless = "#result == null", cacheManager = ONE_DAY)
      }
    )
    @Override
    public Serve getById(Long id) {
        if(ObjectUtils.isNull(id)) {
            return new Serve();
        }

        Serve serve = baseMapper.selectById(id);
        if(ObjectUtils.isNull(serve)) {
            return new Serve();
        }

        return serve;
    }

    /**
     * 查询服务详情信息
     * @param id 服务id
     * @return List
     */
    @Override
    public ServeAggregationSimpleResDTO serveParticularsInfo(Long id) {
        // 查询服务信息
        Serve serve = getById(id);
        // 查询服务项信息
        ServeItemResDTO serveItem
                = serveItemService.queryServeItemAndTypeById(serve.getServeItemId());

        // 封装数据
        ServeAggregationSimpleResDTO sass = new ServeAggregationSimpleResDTO();
        sass.setId(serve.getId());
        sass.setServeItemId(serve.getServeItemId());
        sass.setServeItemName(serveItem.getName());
        sass.setServeItemImg(serveItem.getImg());
        sass.setUnit(serveItem.getUnit());
        sass.setPrice(serve.getPrice());
        sass.setDetailImg(serveItem.getDetailImg());
        sass.setCityCode(serve.getCityCode());

        return sass;
    }

    /**
     * 远程调用查询服务信息接口
     * @param serveId 服务id
     * @return ServeResDTO
     */
    @Override
    public ServeAggregationResDTO getServeInfo(Long serveId) {
        ServeAggregationResDTO serveInfo = baseMapper.getServeInfo(serveId);
        return serveInfo;
    }

    @Resource
    private ServeTypeMapper serveTypeMapper;
    @Resource
    private ServeSyncMapper serveSyncMapper;

    /**
     * 添加区域服务时将数据同步到服务数据同步表中
     * @param serveId 区域服务id
     */
    private void dataSync(Long serveId) {
        // 区域服务数据
        Serve serve = baseMapper.selectById(serveId);
        // 服务项数据
        ServeItem serveItem = serveItemService.getById(serve.getServeItemId());
        // 服务类型数据
        ServeType serveType = serveTypeMapper.selectById(serveItem.getServeTypeId());

        // 封装数据写入数据库
        ServeSync serveSync = new ServeSync();
        serveSync.setId(serve.getId());
        serveSync.setServeItemName(serveItem.getName());
        serveSync.setServeTypeId(serveType.getId());
        serveSync.setServeItemId(serveItem.getId());
        serveSync.setCityCode(serve.getCityCode());
        serveSync.setPrice(serve.getPrice());
        serveSync.setIsHot(serve.getIsHot());
        serveSync.setHotTimeStamp(serve.getHotTimeStamp());
        serveSync.setServeItemSortNum(serveItem.getSortNum());
        serveSync.setServeTypeSortNum(serveType.getSortNum());
        serveSync.setServeTypeName(serveType.getName());
        serveSync.setServeTypeImg(serveType.getImg());
        serveSync.setServeTypeIcon(serveType.getServeTypeIcon());
        serveSync.setUnit(serveItem.getUnit());
        serveSync.setDetailImg(serveItem.getDetailImg());
        serveSync.setServeItemImg(serveItem.getImg());
        serveSync.setServeItemIcon(serveItem.getServeItemIcon());
        serveSyncMapper.insert(serveSync);
    }
}